package com.zhaopin.netty.guanwang;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class TimeServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 1、如前所述，该channelActive()方法将在建立连接并准备好生成流量时调用。让我们在这个方法中写一个 32 位整数来表示当前时间。
     *
     * 2、要发送新消息，我们需要分配一个新的缓冲区来包含该消息。我们将要写入一个 32 位整数，因此我们需要ByteBuf容量至少为 4 个字节的 a。获取当前ByteBufAllocator通孔ChannelHandlerContext.alloc()并分配一个新缓冲区。
     *
     * 3、像往常一样，我们编写构造的消息。
     * 但是等等，翻转在哪里？java.nio.ByteBuffer.flip()之前我们不是在蔚来发消息之前先打电话吗？ByteBuf没有这样的方法，因为它有两个指针；
     * 一个用于读操作，另一个用于写操作。当你写一些东西ByteBuf而读者索引不会改变时，作者索引会增加。读取器索引和写入器索引分别表示消息开始和结束的位置。
     * 相比之下，NIO 缓冲区没有提供一种干净的方法来确定消息内容的开始和结束位置，而无需调用翻转方法。当您忘记翻转缓冲区时，您会遇到麻烦，因为不会发送任何数据或不正确的数据。
     * 这种错误在 Netty 中不会发生，因为我们针对不同的操作类型有不同的指针。当你习惯了它时，你会发现它会让你的生活变得更轻松——一种没有生气的生活！
     * 另一点要注意的是ChannelHandlerContext.write()(and writeAndFlush()) 方法返回一个ChannelFuture. AChannelFuture表示尚未发生的 I/O 操作。
     * 这意味着，任何请求的操作可能尚未执行，因为所有操作在 Netty 中都是异步的。例如，以下代码甚至可能在发送消息之前关闭连接：
     * 因此，您需要在close()方法ChannelFuture返回的完成后调用该方法write()，并在写入操作完成时通知其侦听器。请注意，close()也可能不会立即关闭连接，而是返回一个ChannelFuture.
     *
     * 4、那么当写请求完成时我们如何得到通知？这就像ChannelFutureListener在返回的ChannelFuture. 在这里，我们创建了一个新的匿名函数ChannelFutureListener，它Channel在操作完成时关闭。
     *   或者，您可以使用预定义的侦听器简化代码：
     * @param ctx
     */
    @Override
    public void channelActive(final ChannelHandlerContext ctx) { // (1)
        final ByteBuf time = ctx.alloc().buffer(4); // (2)
        time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
        
        final ChannelFuture f = ctx.writeAndFlush(time); // (3)
        f.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                assert f == future;
                ctx.close();
            }
        }); // (4)
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}